/*
* Copyright (C) 2010-2012 Magnus Skjegstad
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
* 
* The latest version of this library can be downloaded from http://mist-pubsub.googlecode.com
* 
*/
package com.skjegstad.mist2.demos;

import com.skjegstad.mist2.IMistSubscriptionListener;
import com.skjegstad.mist2.MistCoreManager;
import com.skjegstad.mist2.datatypes.DataElement;
import com.skjegstad.mist2.datatypes.NodeIdentifier;
import com.skjegstad.mist2.datatypes.TopicIdentifier;
import com.skjegstad.mist2.exceptions.MistException;
import com.skjegstad.mist2.exceptions.MistHashCollisionException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 *
 * @author Magnus Skjegstad
 */
public class TestChatText {

    private MistCoreManager mist = new MistCoreManager();
    private static final TopicIdentifier MSG_T = new TopicIdentifier("no.ffi.chat.messages");
    private static final TopicIdentifier CMD_T = new TopicIdentifier("no.ffi.chat.commands");
    private final Map<NodeIdentifier, String> nicks = new HashMap();
    private int publishTimeout = 120000;

    public void initMist(String nick, boolean debug, int periodicBeaconTime, int publishTimeout) throws MistException, UnknownHostException {
        //mist.enableTCPServer(5579 + (r.nextInt() % 100));

        //mist.enableMulticast(InetAddress.getByName("224.0.0.1"), 1234);
        
        // Start manually and add config for periodicBeaconTime.
        // -1 == use default
        Properties config = new Properties();
        if (periodicBeaconTime > -1)
            config.setProperty("periodicBeaconTime", "" + periodicBeaconTime);
        mist.addUDPBroadcastModule(InetAddress.getByName("224.0.0.1"),
                1234, true,
                config, null);

        mist.subscribe(MSG_T, new IMistSubscriptionListener() {
            public void deliverMessage(DataElement message) {
                hearMsg(message);
            }
        });
        mist.subscribe(CMD_T, new IMistSubscriptionListener() {
            public void deliverMessage(DataElement message) {
                hearCommand(message);
            }
        });/*
        mist.subscribe(new TopicIdentifier("hei"), new IMistSubscriptionListener() {
            public void deliverMessage(DataElement message) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        }); */
        mist.setDebug(debug);
        mist.start();

        if (nick != null && !nick.isEmpty())
            sayCommand("nick", new String[] {nick});
    }

    public void sayCommand(String command, String[] params) throws MistHashCollisionException {
        String s = command;
        for (String p : params)
            s = s + ";" + p;
        mist.publish(CMD_T, s.getBytes(), publishTimeout);
    }

    public String getNick(NodeIdentifier n) {
        String s = nicks.get(n);
        if (s == null)
            s = n.getNodeIdentifier().toString();
        return s;
    }

    public void stop() {
        mist.stop();
    }

    public void hearCommand(DataElement element) {
        //System.out.println("in cmd");

        String s = new String(element.getPayload());
        String[] line = s.split(";");

        if (line.length < 2)
            return;

        String command = line[0];
        String[] params = Arrays.copyOfRange(line, 1, line.length);

        //System.out.println("got cmd: " + command + " " + params[0]);

        if (command.equalsIgnoreCase("nick")) {
            String oldNick = getNick(element.getSourceNode());
            nicks.put(element.getSourceNode(), params[0]);
            System.out.println("** " + oldNick + " is now known as " + params[0]);
        }
    }

    public void  say(String msg) throws MistHashCollisionException {
        mist.publish(MSG_T, msg.getBytes(), publishTimeout);
    }

    public void  hearMsg(DataElement element) {
        String msg = new String(element.getPayload());
        String nick = getNick(element.getSourceNode());

        Calendar c = Calendar.getInstance();
        String ts = c.get(Calendar.HOUR_OF_DAY) + ":" +
                c.get(Calendar.MINUTE) + "," +
                c.get(Calendar.SECOND);
        System.out.println(nick + " ["+ ts + ", -" + element.getAge() + "ms]: " + msg);
    }

    public static void main(String[] argv) throws MistException, UnknownHostException, IOException {
        String nick = null;
        boolean enableDebug = true;
        if (argv.length > 0) {
            System.out.println("You are " + argv[0]);
            nick = argv[0];
        }
        if (argv.length > 1)
            enableDebug = true;

        TestChatText chatter = new TestChatText();

        chatter.initMist(nick, enableDebug, -1, 120 * 1000);

        System.out.println("Enter message or command. Type /quit to exit.");
        
        String cmd = "";
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (cmd != null && !cmd.equalsIgnoreCase("/quit")) {
            cmd = reader.readLine();

            if (cmd != null && !cmd.trim().isEmpty()) {
                cmd = cmd.trim();
                if (cmd.length() > 0 && cmd.charAt(0) != '/') {
                    chatter.say(cmd);
                } else {
                    String[] commandLine = cmd.split(" ");
                    String command = commandLine[0];

                    if (command.startsWith("/")) {
                        chatter.sayCommand(command.substring(1), Arrays.copyOfRange(commandLine,1, commandLine.length));
                        System.out.println("you sent command " + command.substring(1));
                        //nicks.put(mist.getMyNodeId(), commandLine[1]);
                        //System.out.println("** You are now known as " + commandLine[1]);
                    }
                }
            }
        }

        System.out.println("Exiting.");

        chatter.stop();
    }
}
